//////////////////////////////////////////////////////////////////////
//
//	University of Leeds
//	COMP 5812M Foundations of Modelling & Rendering
//	User Interface for Coursework
//
//	September, 2020
//
//  -----------------------------
//  Raytrace Render Widget
//  -----------------------------
//
//	Provides a widget that displays a fixed image
//	Assumes that the image will be edited (somehow) when Render() is called
//  
////////////////////////////////////////////////////////////////////////

// include guard
#ifndef RAYTRACE_RENDER_WIDGET_H
#define RAYTRACE_RENDER_WIDGET_H

#include <vector>
#include <mutex>
#include <thread>

// include the relevant QT headers
#include <QOpenGLWidget>
#include <QMouseEvent>

// and include all of our own headers that we need
#include "ThreeDModel.h"
#include "RenderParameters.h"
#include "ray.h"
#include "scene.h"

// class for a render widget with arcball linked to an external arcball widget
class RaytraceRenderWidget : public QOpenGLWidget										
	{ // class RaytraceRenderWidget
	Q_OBJECT
	private:	
	// the geometric object to be rendered
    std::vector<ThreeDModel> *texturedObjects;
    std::thread raytracingThread;
	// the render parameters to use
	RenderParameters *renderParameters;

	// An image to use as a framebuffer
	RGBAImage frameBuffer;


	public:
	// constructor
	RaytraceRenderWidget
			(
	 		// the geometric object to show
            std::vector<ThreeDModel> 		*newTexturedObject,
			// the render parameters to use
			RenderParameters 	*newRenderParameters,
			// parent widget in visual hierarchy
			QWidget 			*parent
			);
	
	// destructor
	~RaytraceRenderWidget();

    Scene *scene = new Scene(texturedObjects, renderParameters);

    // routine that generates the image
    void Raytrace();

    void newRaytraceThread();

    //根据表面法线反射光线
    Ray reflectRay(Ray r,Cartesian3 normal,Cartesian3 hitpoint);

    // Recursive ray tracing function
    Homogeneous4 TraceAndShadeWithRay(Ray r,int recursinDepth,float weight);

    Homogeneous4 RefractionWithFrensel(Ray r,int recursionDepth,float weight);

    //计算折射方向
    Ray refractRay(Ray r,Cartesian3 normal,Cartesian3 hitpoint, float etai, float etat);

    // 使用Schlick近似来计算反射率
    float fresnel(const Cartesian3& I, const Cartesian3& N, float ior);


    //Montecarlo sampling for indirect lighting
    Homogeneous4 Montecarlosampling(Ray r,int recursionDepth, float weight);

    // 随机方向生成函数
    Cartesian3 randomDirectionInHemisphere(Cartesian3 normal);
    //计算直接光照，包括阴影处理
    Homogeneous4 CalculateDirectIllumination(Cartesian3 newintersectP, Cartesian3 intersectNormal, Scene::CollisionInfo newci, Cartesian3 newbc);

    void RaytraceThread();

    void forceRepaint();

    // given a pixel position, casts a ray towards the scene
    Ray calculateRay(int pixelx, int pixely, bool perspective);


			
	protected:
	// called when OpenGL context is set up
	void initializeGL();
	// called every time the widget is resized
	void resizeGL(int w, int h);
	// called every time the widget needs painting
	void paintGL();

	// mouse-handling
	virtual void mousePressEvent(QMouseEvent *event);
	virtual void mouseMoveEvent(QMouseEvent *event);
	virtual void mouseReleaseEvent(QMouseEvent *event);

    private:

	signals:
	// these are general purpose signals, which scale the drag to 
	// the notional unit sphere and pass it to the controller for handling
	void BeginScaledDrag(int whichButton, float x, float y);
	// note that Continue & End assume the button has already been set
	void ContinueScaledDrag(float x, float y);
	void EndScaledDrag(float x, float y);



	}; // class RaytraceRenderWidget

#endif
